import os
import subprocess
from _md5 import md5
import multiprocessing

from alibabacloud_ecs20140526.client import Client as Ecs20140526Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_ecs20140526 import models as ecs_20140526_models
from alibabacloud_tea_util import models as util_models
from ping3 import ping
import rsa


def init_dir(dir_name):
    # 判断目录是否存在
    if not os.path.exists(dir_name):
        os.mkdir(dir_name)


def init_certificate(dir_name):
    # 判断证书是否存在
    if not os.path.exists(dir_name + '/public.pem') or not os.path.exists(dir_name + '/private.pem'):
        # 删除证书
        if os.path.exists(dir_name + '/public.pem'):
            os.remove(dir_name + '/public.pem')
        if os.path.exists(dir_name + '/private.pem'):
            os.remove(dir_name + '/private.pem')
        # 生成证书
        (pubkey, privkey) = rsa.newkeys(2048)
        with open(dir_name + '/public.pem', 'w') as f:
            f.write(pubkey.save_pkcs1().decode())
        with open(dir_name + '/private.pem', 'w') as f:
            f.write(privkey.save_pkcs1().decode())


def run_ssh():
    ip = '47.91.23.66'
    port = 10821
    ssh = subprocess.Popen('ssh -i ~/.ssh/id_rsa -D {} root@{}'.format(port, ip), stdout=subprocess.PIPE)
    return ssh.pid


def run_ssh_c(ssh):
    print(ssh)


def run_ping(ping_region):
    second = ping(ping_region['region_endpoint'])
    if second:
        ping_region['ping'] = int(second * 1000)
    else:
        ping_region['ping'] = 1000000
    return tuple([ping_region['region_id'], ping_region['ping']])


def run_ping_c(response):
    # 从数组里面取值
    response_region_id, run_ping_ping = response
    global regions_dict
    response_region = regions_dict[response_region_id]
    response_region['ping'] = run_ping_ping


def get_instances(get_instances_region, access_key_id_run, access_key_secret_run):
    config_all = open_api_models.Config(
        # 您的AccessKey ID,
        access_key_id=access_key_id_run,
        # 您的AccessKey Secret,
        access_key_secret=access_key_secret_run
    )
    config_run = config_all
    config_run.endpoint = get_instances_region['region_endpoint']
    client_run = Ecs20140526Client(config_run)
    runtime_run = util_models.RuntimeOptions()
    # 获取当前选取的ecs列表
    describe_instances_request = ecs_20140526_models.DescribeInstancesRequest(
        region_id=get_instances_region['region_id'],
        instance_name='aliproxy*'
    )
    describe_instances_response = client_run.describe_instances_with_options(describe_instances_request, runtime_run)
    return tuple([get_instances_region, describe_instances_response])


def get_instances_c(response):
    # 从数组里面取值
    get_instances_region, instances = response
    global regions_dict
    response_region = regions_dict[get_instances_region['region_id']]
    instances_list = {}
    for instance in instances.body.instances.instance:
        instances_list[instance.instance_id] = {
            'instance_id': instance.instance_id,
            'detail': instance,
        }
    response_region['instances'] = instances_list


def describe_images(describe_images_region, access_key_id_run, access_key_secret_run):
    config_all = open_api_models.Config(
        # 您的AccessKey ID,
        access_key_id=access_key_id_run,
        # 您的AccessKey Secret,
        access_key_secret=access_key_secret_run
    )
    config_run = config_all
    config_run.endpoint = describe_images_region['region_endpoint']
    client_run = Ecs20140526Client(config_run)
    runtime_run = util_models.RuntimeOptions()
    # 获取当前选取的ecs列表
    describe_images_request = ecs_20140526_models.DescribeImagesRequest(
        region_id=describe_images_region['region_id'],
        ostype='linux',
    )
    describe_images_response = client_run.describe_images_with_options(describe_images_request,
                                                                       runtime_run)
    return tuple([describe_images_region, describe_images_response])


def describe_images_c(response):
    # 从数组里面取值
    describe_images_region, images = response
    global regions_dict
    response_region = regions_dict[describe_images_region['region_id']]
    images_list = {}
    for image in images.body.images.image:
        images_list[image.image_id] = {
            'image_id': image.image_id,
            'detail': image,
        }
    response_region['images'] = images_list


def describe_security_groups(describe_security_groups_region, access_key_id_run, access_key_secret_run):
    config_all = open_api_models.Config(
        # 您的AccessKey ID,
        access_key_id=access_key_id_run,
        # 您的AccessKey Secret,
        access_key_secret=access_key_secret_run
    )
    config_run = config_all
    config_run.endpoint = describe_security_groups_region['region_endpoint']
    client_run = Ecs20140526Client(config_run)
    runtime_run = util_models.RuntimeOptions()
    # 获取当前选取的ecs列表
    describe_security_groups_request = ecs_20140526_models.DescribeSecurityGroupsRequest(
        region_id=describe_security_groups_region['region_id'],
    )
    describe_security_groups_response = client_run.describe_security_groups_with_options(
        describe_security_groups_request,
        runtime_run)
    return tuple([describe_security_groups_region, describe_security_groups_response])


def describe_security_groups_c(response):
    # 从数组里面取值
    describe_security_groups_region, security_groups = response
    global regions_dict
    response_region = regions_dict[describe_security_groups_region['region_id']]
    security_groups_list = {}
    for security_group in security_groups.body.security_groups.security_group:
        security_groups_list[security_group.security_group_id] = {
            'security_group_id': security_group.security_group_id,
            'detail': security_group,
        }
    response_region['security_groups'] = security_groups_list


def get_available_resource(available_resource_region, resource_type, access_key_id_run, access_key_secret_run,
                           resource=None):
    config_all = open_api_models.Config(
        # 您的AccessKey ID,
        access_key_id=access_key_id_run,
        # 您的AccessKey Secret,
        access_key_secret=access_key_secret_run
    )
    config_run = config_all
    config_run.endpoint = available_resource_region['region_endpoint']
    client_run = Ecs20140526Client(config_run)
    runtime_run = util_models.RuntimeOptions()
    if resource_type == 'InstanceType':
        describe_available_resource_request = ecs_20140526_models.DescribeAvailableResourceRequest(
            region_id=available_resource_region['region_id'],
            destination_resource=resource_type,
            instance_charge_type='PostPaid',
            spot_strategy='SpotAsPriceGo'
        )
    if resource_type == 'SystemDisk':
        describe_available_resource_request = ecs_20140526_models.DescribeAvailableResourceRequest(
            region_id=available_resource_region['region_id'],
            destination_resource=resource_type,
            resource_type='instance',
            instance_type='ecs.n1.small'
        )
    available_resource_response = client_run.describe_available_resource_with_options(
        describe_available_resource_request,
        runtime_run)
    return tuple([available_resource_region, resource_type, available_resource_response, resource])


def get_available_resource_c(response):
    available_resource_region, resource_type, available_resource, resource = response
    global regions_dict
    response_region = regions_dict[available_resource_region['region_id']]
    if resource_type == 'InstanceType':
        response_region[resource_type] = available_resource.body
        response_region['zones'] = {}
        response_region['resources'] = {}
        for AvailableZone in available_resource.body.available_zones.available_zone:
            response_region['zones'][AvailableZone.zone_id] = {
                'zone_id': AvailableZone.zone_id,
            }
            for AvailableResource in AvailableZone.available_resources.available_resource:
                for SupportedResource in AvailableResource.supported_resources.supported_resource:
                    # 如果value 以 ecs.t 开头
                    if SupportedResource.value.startswith('ecs.t'):
                        response_region['resources'][AvailableZone.zone_id + SupportedResource.value] = {
                            'region_id': available_resource_region['region_id'],
                            'zone_id': AvailableZone.zone_id,
                            'status': SupportedResource.status,
                            'status_category': SupportedResource.status_category,
                            'value': SupportedResource.value,
                            'price': 9999999,
                            'detail': SupportedResource,
                        }
    if resource_type == 'SystemDisk':
        response_region['resources'][resource['zone_id'] + resource['value']][resource_type] = available_resource.body
        response_region['resources'][resource['zone_id'] + resource['value']]['disks'] = {}
        # 如果存在available_resource.body.available_zones
        if available_resource.body.available_zones:
            for AvailableZone in available_resource.body.available_zones.available_zone:
                for AvailableResource in AvailableZone.available_resources.available_resource:
                    for SupportedResource in AvailableResource.supported_resources.supported_resource:
                        response_region['resources'][resource['zone_id'] + resource['value']]['disks'][
                            SupportedResource.value] = {
                            'region_id': available_resource_region['region_id'],
                            'zone_id': AvailableZone.zone_id,
                            'instance': resource['value'],
                            'status': SupportedResource.status,
                            'unit': SupportedResource.unit,
                            'max': SupportedResource.max,
                            'min': SupportedResource.min,
                            'value': SupportedResource.value,
                            'price': 9999999,
                            'detail': SupportedResource,
                        }


def get_describe_price(describe_price_region, resource_type, access_key_id_run, access_key_secret_run, resource=None,
                       disk=None):
    config_all = open_api_models.Config(
        # 您的AccessKey ID,
        access_key_id=access_key_id_run,
        # 您的AccessKey Secret,
        access_key_secret=access_key_secret_run
    )
    config_run = config_all
    config_run.endpoint = describe_price_region['region_endpoint']
    client_run = Ecs20140526Client(config_run)
    runtime_run = util_models.RuntimeOptions()
    system_disk = ecs_20140526_models.DescribePriceRequestSystemDisk(
        category=disk['value'],
        size=disk['min'],
    )
    describe_price_request = ecs_20140526_models.DescribePriceRequest(
        region_id=describe_price_region['region_id'],
        resource_type=resource_type,
        instance_type=resource['value'],
        spot_strategy='SpotAsPriceGo',
        spot_duration=0
    )
    describe_price_response = client_run.describe_price_with_options(
        describe_price_request,
        runtime_run)
    return tuple([describe_price_region, resource_type, describe_price_response, resource, disk])


def get_describe_price_c(response):
    describe_price_region, resource_type, describe_price, resource, disk = response
    global regions_dict
    response_region = regions_dict[describe_price_region['region_id']]
    response_region['resources'][resource['zone_id'] + resource['value']]['disks'][disk['value']][
        'price_detail'] = describe_price.body
    response_region['resources'][resource['zone_id'] + resource['value']]['disks'][disk['value']][
        'price'] = describe_price.body.price_info.price.trade_price


def error_callback(response):
    print(3, response)


if __name__ == '__main__':
    globals()
    access_key_id = 'LTAI5tRrwypSzHqdoiF7FDdh'
    access_key_secret = 'wE0YYHxEnB89IHyN4WKCPuEwyzyMl4'
    config_path = '.aliproxy'
    certificate_path = '.ssh'
    ssh_pool = multiprocessing.Pool(processes=1)
    # 获取用户目录地址
    home_dir = os.path.expanduser('~').replace('\\', '/')
    config_dir = home_dir + '\\' + config_path
    certificate_dir = config_dir + '\\' + certificate_path
    init_dir(config_dir)
    init_dir(certificate_dir)
    init_certificate(certificate_dir)

    # 取出证书
    public_key = open(certificate_dir + '/public.pem').read()
    private_key = open(certificate_dir + '/private.pem').read()

    # MD5加密private_key取前10位
    key = md5(private_key.encode()).hexdigest()[:10]

    # 创建ssh密钥对

    config = open_api_models.Config(
        # 您的AccessKey ID,
        access_key_id=access_key_id,
        # 您的AccessKey Secret,
        access_key_secret=access_key_secret
    )
    # 访问的域名
    config.endpoint = f'ecs.ap-northeast-1.aliyuncs.com'
    EcsClient = Ecs20140526Client(config)
    runtime = util_models.RuntimeOptions()
    # 获取所有可用区列表
    describe_regions_request = ecs_20140526_models.DescribeRegionsRequest()
    DescribeRegionsResponse = EcsClient.describe_regions_with_options(describe_regions_request, runtime)
    # 可用区列表
    regions = DescribeRegionsResponse.body.regions.region
    # 以region_id为key，regions为value存入字典
    regions_dict = {}
    overseas_regions_dict = {}
    select_regions_dict = {}
    for region in regions:
        # region转成字典
        regions_dict[region.region_id] = {
            'region_id': region.region_id,
            'region_endpoint': region.region_endpoint,
            'local_name': region.local_name,
        }
        if region.region_id[:2] != 'cn':
            overseas_regions_dict[region.region_id] = regions_dict[region.region_id]
    work_pool = multiprocessing.Pool(processes=10)
    # 循环字典，每个进程调用run_ping函数
    for index, region in regions_dict.items():
        # 对每一个region进行ping
        work_pool.apply_async(run_ping, (region,), callback=run_ping_c)
        # 获取每一个可用区的ecs列表
        work_pool.apply_async(get_instances, (region, access_key_id, access_key_secret), callback=get_instances_c)
    work_pool.close()
    work_pool.join()
    work_pool.terminate()
    # regions_dict按ping值排序
    regions_list = sorted(regions_dict.items(), key=lambda x: x[1]['ping'])
    overseas_regions_list = sorted(overseas_regions_dict.items(), key=lambda x: x[1]['ping'])
    work_pool = multiprocessing.Pool(processes=10)
    for region_id, region in overseas_regions_dict.items():
        # 获取每个可用区的资源列表
        work_pool.apply_async(get_available_resource, (region, 'InstanceType', access_key_id, access_key_secret),
                              callback=get_available_resource_c)
    work_pool.close()
    work_pool.join()
    work_pool.terminate()
    work_pool = multiprocessing.Pool(processes=20)
    for region_id, region in overseas_regions_dict.items():
        if 'resources' in region:
            for resource_id in region['resources']:
                work_pool.apply_async(get_available_resource,
                                      (region, 'SystemDisk', access_key_id, access_key_secret,
                                       region['resources'][resource_id]),
                                      callback=get_available_resource_c)
    work_pool.close()
    work_pool.join()
    work_pool.terminate()
    work_pool = multiprocessing.Pool(processes=20)
    for region_id, region in overseas_regions_dict.items():
        if 'resources' in region:
            for resource_id in region['resources']:
                if 'disks' in region['resources'][resource_id]:
                    for disk_id in region['resources'][resource_id]['disks']:
                        work_pool.apply_async(get_describe_price,
                                              (region, 'instance', access_key_id, access_key_secret,
                                               region['resources'][resource_id],
                                               region['resources'][resource_id]['disks'][disk_id]),
                                              callback=get_describe_price_c)
    work_pool.close()
    work_pool.join()
    work_pool.terminate()
    # ssh_pool.apply_async(run_ssh, callback=run_ssh_c)
    for region_id, region in overseas_regions_dict.items():
        region['price'] = 9999999
        if 'resources' in region:
            for resource_id in region['resources']:
                if 'disks' in region['resources'][resource_id]:
                    for disk_id in region['resources'][resource_id]['disks']:
                        if 'price' in region['resources'][resource_id]['disks'][disk_id]:
                            old_price = region['price']
                            region['price'] = min(region['price'],
                                                  region['resources'][resource_id]['disks'][disk_id]['price'])
                            if old_price != region['price']:
                                region['resource'] = region['resources'][resource_id]['disks'][disk_id]

    for region_id, region in regions_list:
        if 'price' in region:
            print(region_id, region['ping'], region['price'])
        else:
            print(region_id, region['ping'], 'no price')

    select_region_id = 'ap-northeast-1'

    select_region = regions_dict[select_region_id]

    #     获取可用区的镜像
    #     获取可用区的安全组
    #     获取可用区的交换机
    #     获取可用区的带宽信息
    work_pool = multiprocessing.Pool(processes=10)
    work_pool.apply_async(describe_images, (select_region, access_key_id, access_key_secret),
                          callback=describe_images_c)
    work_pool.apply_async(describe_security_groups, (select_region, access_key_id, access_key_secret),
                          callback=describe_security_groups_c, error_callback=error_callback)
    work_pool.close()
    work_pool.join()
    work_pool.terminate()
    print(select_region)
